home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume17 / malias < prev    next >
Encoding:
Internet Message Format  |  1989-02-08  |  14.2 KB

  1. Subject:  v17i094:  Expand .mailrc aliases
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Mark Sirota <msir_cif@uhura.cc.rochester.edu>
  6. Posting-number: Volume 17, Issue 94
  7. Archive-name: malias
  8.  
  9. malias: Decode mail aliases.
  10.  
  11. Returns true address of all arguments, decoded from alias
  12. lines in your .mailrc.
  13.  
  14. Results are returned in stream form, so
  15.     % malias mark larry
  16. might return
  17.     msir_ltd@uhura.cc.rochester.edu lm03_ltd@uhura.cc.rochester.edu
  18. so that the results can be passed on to some other program, as in
  19.     % finger `malias cif`
  20. to finger everyone you know on CIF.
  21.  
  22. --
  23. Mark Sirota - University of Rochester, Rochester, NY
  24.  Internet: msir_cif@uhura.cc.rochester.edu
  25.  Bitnet:   msir_ss@uordbv.bitnet
  26.  UUCP:     ...!rochester!ur-cc!msir_cif
  27.  
  28. #! /bin/sh
  29. # This is a shell archive.  Remove anything before this line, then unpack
  30. # it by saving it into a file and typing "sh file".  To overwrite existing
  31. # files, type "sh file -c".  You can also feed this as standard input via
  32. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  33. # will see the following message at the end:
  34. #        "End of shell archive."
  35. # Contents:  README Makefile malias.c malias.1
  36. # Wrapped by msir_cif@uhura.cc.rochester.edu on Tue Feb  7 15:38:48 1989
  37. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  38. if test -f 'README' -a "${1}" != "-c" ; then 
  39.   echo shar: Will not clobber existing file \"'README'\"
  40. else
  41. echo shar: Extracting \"'README'\" \(393 characters\)
  42. sed "s/^X//" >'README' <<'END_OF_FILE'
  43. X#
  44. X# README for malias
  45. X#
  46. X
  47. XThis program is Copyright (c) 1988, 1989 by Mark Sirota.
  48. XIt is provided to you without charge, and with no warranty.
  49. XYou may give away copies if malias, including sources, provided that this
  50. Xnotice is included in all the files.
  51. X
  52. XIn other words, you can do whatever you want with it, so long as you don't
  53. Xmake any money from it and credit is given where credit is due.
  54. END_OF_FILE
  55. if test 393 -ne `wc -c <'README'`; then
  56.     echo shar: \"'README'\" unpacked with wrong size!
  57. fi
  58. # end of 'README'
  59. fi
  60. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  61.   echo shar: Will not clobber existing file \"'Makefile'\"
  62. else
  63. echo shar: Extracting \"'Makefile'\" \(396 characters\)
  64. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  65. X#
  66. X# Makefile for malias
  67. X#
  68. X
  69. X#
  70. X# Update the following directories for your installation.
  71. X#
  72. XBINDIR = /u/cif/bin
  73. XMANDIR = /u/cif/man
  74. XMANEXT = 1
  75. X
  76. XCFLAGS = -O
  77. X
  78. Xmalias: malias.c
  79. X    cc $(CFLAGS) -o malias
  80. X
  81. Xinstall: malias
  82. X    install -s malias $(BINDIR)
  83. X    install -m 0644 malias.1 $(MANDIR)/man$(MANEXT)/malias.$(MANEXT)
  84. X
  85. Xclean:
  86. X    rm -f malias core
  87. X
  88. Xshar:
  89. X    shar -o malias.shar README Makefile malias.c malias.1
  90. END_OF_FILE
  91. if test 396 -ne `wc -c <'Makefile'`; then
  92.     echo shar: \"'Makefile'\" unpacked with wrong size!
  93. fi
  94. # end of 'Makefile'
  95. fi
  96. if test -f 'malias.c' -a "${1}" != "-c" ; then 
  97.   echo shar: Will not clobber existing file \"'malias.c'\"
  98. else
  99. echo shar: Extracting \"'malias.c'\" \(8203 characters\)
  100. sed "s/^X//" >'malias.c' <<'END_OF_FILE'
  101. X/*
  102. X * malias: Decode mail aliases.  Returns true address of all arguments,
  103. X * decoded from alias lines in your .mailrc.
  104. X *
  105. X * Usage: malias <alias> [alias] ...
  106. X *
  107. X * Results are returned in stream form, so
  108. X *     % malias mark larry
  109. X * might return
  110. X *    msir_ltd@uhura.cc.rochester.edu lm03_ltd@uhura.cc.rochester.edu
  111. X * so that the results can be passed on to some other program, as in
  112. X *    finger `malias cif`
  113. X * to finger everyone you know on CIF.
  114. X *
  115. X * Mark Sirota (msir_cif@uhura.cc.rochester.edu), Fall 1988
  116. X */
  117. X
  118. X/*
  119. X * The program reads the .mailrc and saves the aliases in trie format.
  120. X * The leaves of the trie are linked lists of addresses.  Each address may
  121. X * itself be an alias.
  122. X *
  123. X * The name of the .mailrc is determined by the environment variable MAILRC.
  124. X * If not present, $HOME/.mailrc is assumed.  The "-f" option overrides this.
  125. X */
  126. X
  127. X#include <stdio.h>
  128. X#include <string.h>
  129. X#include <malloc.h>
  130. X
  131. X/*
  132. X * Aliases are maintained as a binding of a name to a mailing list (which may
  133. X * contain one or more names).  Names in a list may themselves be aliases.
  134. X * This structure is one of the names in a mailing list.
  135. X */
  136. Xstruct address {
  137. X    char        *address;
  138. X    struct address    *next,
  139. X            *prev;
  140. X};
  141. X
  142. X/*
  143. X * Ways of finding an alias in the trie.
  144. X */
  145. X#define A_NOTFOUND    -1            /* Not in the trie */
  146. X#define A_USED        0            /* Found, but already seen */
  147. X#define A_FOUND        1            /* Found and okay */
  148. X
  149. X#define FALSE    0
  150. X#define TRUE    1
  151. X
  152. Xvoid
  153. Xusage(progname)
  154. Xchar    *progname;
  155. X{
  156. X    fprintf(stderr, "Usage: %s [-,] [-1] [-f filename] <alias ...>\n", progname);
  157. X}
  158. X
  159. Xvoid
  160. Xmain(argc, argv)
  161. Xint    argc;
  162. Xchar    **argv;
  163. X{
  164. X    int        c;
  165. X    extern int    optind;
  166. X    extern char    *optarg;
  167. X    int        commaflag = FALSE;
  168. X    int        oneflag = FALSE;
  169. X    char        *filename = (char *) NULL;
  170. X    char        **root;
  171. X    extern char    *calloc();
  172. X    void        mailrc();
  173. X    struct address    *list = (struct address *) NULL,
  174. X            *l,
  175. X            *lprev;
  176. X    void        lookup();
  177. X
  178. X    /*
  179. X     * Parse the arguments.
  180. X     */
  181. X    while ((c = getopt(argc, argv, ",1f:")) != EOF)
  182. X        switch (c) {
  183. X            case ',':
  184. X            commaflag = TRUE;
  185. X            break;
  186. X            case '1':
  187. X            oneflag = TRUE;
  188. X            break;
  189. X            case 'f':
  190. X            filename = optarg;
  191. X            break;
  192. X            case '?':
  193. X            default:
  194. X            usage(argv[0]);
  195. X            exit(1);
  196. X        }
  197. X
  198. X    /*
  199. X     * If there are no aliases to process, just exit.  This is so that
  200. X     * malias can be used as a front end for other programs, which don't
  201. X     * necessarily take arguments, like finger.
  202. X     */
  203. X    if (optind == argc)
  204. X        exit(0);
  205. X
  206. X    /*
  207. X     * Allocate memory for the root node of the trie
  208. X     */
  209. X    if (!(root = (char **) calloc(128, sizeof (char *)))) {
  210. X        fprintf(stderr, "Out of memory.\n");
  211. X        exit(1);
  212. X    }
  213. X
  214. X    /*
  215. X     * Read lines out of the .mailrc, and add each alias to the trie
  216. X     */
  217. X    mailrc(filename, root);
  218. X
  219. X    /*
  220. X     * Translate argv to a linked list.
  221. X     */
  222. X    for (; optind < argc; optind++) {
  223. X        if (!(l = (struct address *) malloc(sizeof (struct address)))) {
  224. X            fprintf(stderr, "Out of memory.\n");
  225. X            break;
  226. X        }
  227. X
  228. X        if (!list) {
  229. X            list = l;
  230. X            list->prev = (struct address *) NULL;
  231. X        } else {
  232. X            l->prev = lprev;
  233. X            lprev->next = l;
  234. X        }
  235. X        l->address = argv[optind];
  236. X        l->next = (struct address *) NULL;
  237. X        lprev = l;
  238. X    }
  239. X
  240. X    /*
  241. X     * Now look up the list
  242. X     */
  243. X    lookup(root, &list);
  244. X
  245. X    /*
  246. X     * Print the results.
  247. X     */
  248. X    for (l = list; l; l = l->next) {
  249. X        fputs(l->address, stdout);
  250. X        if (l->next) {
  251. X            if (commaflag)
  252. X                putchar(',');
  253. X            if (oneflag)
  254. X                putchar('\n');
  255. X            else
  256. X                putchar(' ');
  257. X        }
  258. X    }
  259. X    putchar('\n');
  260. X}
  261. X
  262. X/*
  263. X * Open the user's .mailrc and add each alias to the trie.  The .mailrc is
  264. X * defined by the environment variable MAILRC.  If not found, $HOME/.mailrc
  265. X * is assumed.
  266. X *
  267. X * The mail command "source", if found in the mailrc, is followed.
  268. X */
  269. Xvoid
  270. Xmailrc(filename, root)
  271. Xchar    *filename;
  272. Xchar    **root;
  273. X{
  274. X    extern char    *getenv();
  275. X    char        buffer[BUFSIZ];
  276. X    FILE        *fp;
  277. X    char        line[BUFSIZ];
  278. X    char        *command;
  279. X    char        *alias;
  280. X    char        *salloc();
  281. X    struct address    *real;
  282. X    struct address    *lalloc();
  283. X    void        addalias();
  284. X
  285. X    if (!filename && !(filename = getenv("MAILRC"))) {
  286. X        sprintf(buffer, "%s/.mailrc", getenv("HOME"));
  287. X        filename = buffer;
  288. X    }
  289. X
  290. X    if (!(fp = fopen(filename, "r"))) {
  291. X        perror(filename);
  292. X        exit(1);
  293. X    }
  294. X
  295. X    while (fgets(line, sizeof line, fp)) {
  296. X        if (!(command = strtok(line, " \t\n")))
  297. X            continue;
  298. X
  299. X        if (strcmp(command, "source") == 0)
  300. X            mailrc(strtok((char *) NULL, "\n"), root);
  301. X        else if (strcmp(command, "alias") == 0) {
  302. X            alias = salloc(strtok((char *) NULL, " \t"));
  303. X            real = lalloc(strtok((char *) NULL, "\n"));
  304. X            addalias(root, alias, real);
  305. X        }
  306. X    }
  307. X
  308. X    fclose(fp);
  309. X}
  310. X
  311. X/*
  312. X * Add an alias to the trie
  313. X */
  314. Xvoid
  315. Xaddalias(root, alias, real)
  316. Xchar        **root;
  317. Xchar        *alias;
  318. Xstruct address    *real;
  319. X{
  320. X    char        **tp;
  321. X    extern char    *calloc();
  322. X
  323. X    /*
  324. X     * Scan down the existing trie as far as we can
  325. X     */
  326. X    tp = root;
  327. X    for (; *alias; alias++) {
  328. X        if (!tp[*alias])
  329. X            break;
  330. X        tp = (char **) tp[*alias];
  331. X    }
  332. X
  333. X    /*
  334. X     * Add the rest of the alias to the trie
  335. X     */
  336. X    for (; *alias; alias++) {
  337. X        if (!(tp[*alias] = calloc(128, sizeof (char *)))) {
  338. X            fprintf(stderr, "Out of memory.\n");
  339. X            exit(1);
  340. X        }
  341. X        tp = (char **) tp[*alias];
  342. X    }
  343. X
  344. X    /*
  345. X     * Set the end of the alias to point to the real name
  346. X     */
  347. X    tp[NULL] = (char *) real;
  348. X}
  349. X
  350. X/*
  351. X * Look up an alias list in the trie.  When finished, the list will contain
  352. X * only resolved names.
  353. X */
  354. Xvoid
  355. Xlookup(root, aliasl)
  356. Xchar        **root;
  357. Xstruct address    **aliasl;
  358. X{
  359. X    struct address    *alias;        /* Current alias pointer */
  360. X    struct address    *list,
  361. X            *l;        /* list associated with alias */
  362. X
  363. X    /*
  364. X     * Look up each alias in this list
  365. X     */
  366. X    alias = *aliasl;
  367. X    while (alias) {
  368. X        switch (findalias(root, alias->address, &list)) {
  369. X            case A_NOTFOUND:
  370. X            /*
  371. X             * Leave this one alone.
  372. X             */
  373. X            alias = alias->next;
  374. X            break;
  375. X            case A_USED:
  376. X            /*
  377. X             * This alias has been processed before.
  378. X             * just remove this alias and move on.
  379. X             */
  380. X            if (alias->prev)
  381. X                alias->prev->next = alias->next;
  382. X            else
  383. X                *aliasl = alias->next;
  384. X            if (alias->next)
  385. X                alias->next->prev = alias->prev;
  386. X            alias = alias->next;
  387. X            break;
  388. X            case A_FOUND:
  389. X            /*
  390. X             * Splice the list in here in place of the alias.
  391. X             */
  392. X            if (alias->prev)
  393. X                alias->prev->next = list;
  394. X            else
  395. X                *aliasl = list;
  396. X            list->prev = alias->prev;
  397. X            for (l = list; l->next; l = l->next)
  398. X                ;
  399. X            l->next = alias->next;
  400. X            if (alias->next)
  401. X                alias->next->prev = l;
  402. X            alias = list;
  403. X            break;
  404. X        }
  405. X    }
  406. X}
  407. X
  408. X/*
  409. X * Find an alias in the trie.  When an alias is fonund, the alias is removed
  410. X * so that it will not be repeated.  The result is placed in list, and the
  411. X * status is returned (NOTFOUND, USED, or FOUND).
  412. X */
  413. Xint
  414. Xfindalias(root, alias, list)
  415. Xchar        **root;
  416. Xchar        *alias;
  417. Xstruct address    **list;
  418. X{
  419. X    char    **tp;
  420. X
  421. X    /*
  422. X     * Scan down the trie
  423. X     */
  424. X    tp = root;
  425. X    for (; *alias; alias++) {
  426. X        if (!tp[*alias])
  427. X            break;
  428. X        tp = (char **) tp[*alias];
  429. X    }
  430. X
  431. X    /*
  432. X     * If we didn't make it to the end of the alias, return NOTFOUND.
  433. X     * Otherwise, return the list.
  434. X     */
  435. X    if (*alias) {
  436. X        *list = (struct address *) NULL;
  437. X        return A_NOTFOUND;
  438. X    }
  439. X
  440. X    /*
  441. X     * Found.  If used, the leaf will be NULL, and so we'll return USED.
  442. X     */
  443. X    if ((struct address *) tp[NULL] == (struct address *) NULL) {
  444. X        *list = (struct address *) NULL;
  445. X        return A_USED;
  446. X    }
  447. X
  448. X    /*
  449. X     * Save a pointer to the list and then remove the trie
  450. X     * reference.  Next time this alias is referenced, it will return a
  451. X     * NULL list.
  452. X     */
  453. X    *list = (struct address *) tp[NULL];
  454. X    tp[NULL] = (char *) NULL;
  455. X    return A_FOUND;
  456. X}
  457. X
  458. X/*
  459. X * Allocate enough new memory to hold string, copy it there, and return a
  460. X * pointer to the new copy.
  461. X */
  462. Xchar *
  463. Xsalloc(string)
  464. Xchar    *string;
  465. X{
  466. X    return strcpy(malloc((unsigned) strlen(string) + 1), string);
  467. X}
  468. X
  469. X/*
  470. X * Take a string and turn it into a linked list of addresses, using spaces
  471. X * and tabs as delimiters.
  472. X */
  473. Xstruct address *
  474. Xlalloc(string)
  475. Xchar    *string;
  476. X{
  477. X    char        *s;
  478. X    struct address    *l,
  479. X            *lprev,
  480. X            *list = (struct address *) NULL;
  481. X    char        *salloc();
  482. X
  483. X    for (s = strtok(string, " \t"); s; s = strtok((char *) NULL, " \t")) {
  484. X        if (!(l = (struct address *) malloc(sizeof (struct address)))) {
  485. X            fprintf(stderr, "Out of memory.\n");
  486. X            return (struct address *) NULL;
  487. X        }
  488. X        if (!list) {
  489. X            list = l;
  490. X            list->prev = (struct address *) NULL;
  491. X        } else {
  492. X            list->prev = lprev;
  493. X            lprev->next = l;
  494. X        }
  495. X        l->address = salloc(s);
  496. X        l->next = (struct address *) NULL;
  497. X        lprev = l;
  498. X    }
  499. X
  500. X    return list;
  501. X}
  502. END_OF_FILE
  503. if test 8203 -ne `wc -c <'malias.c'`; then
  504.     echo shar: \"'malias.c'\" unpacked with wrong size!
  505. fi
  506. # end of 'malias.c'
  507. fi
  508. if test -f 'malias.1' -a "${1}" != "-c" ; then 
  509.   echo shar: Will not clobber existing file \"'malias.1'\"
  510. else
  511. echo shar: Extracting \"'malias.1'\" \(2311 characters\)
  512. sed "s/^X//" >'malias.1' <<'END_OF_FILE'
  513. X.TH MALIAS 1 "21 January 1989"
  514. X.SH NAME
  515. Xmalias \- expand mail aliases
  516. X.SH SYNOPSIS
  517. X\fBmalias\fP [\fB-,\fP] [\fB-1\fP] [\fB-f \fIfilename\fP] [\fIalias ...\fP]
  518. X.SH DESCRIPTION
  519. X\fBmalias\fP decodes alias lines from a mailrc and returns the true
  520. Xaddresses.  By default, the results are returned in stream format so that
  521. Xthe results may be passed on to some other program (See the EXAMPLES section
  522. Xbelow).
  523. X
  524. XThe mailrc is determined by the environment variable \fBMAILRC\fP.  If not
  525. Xset, \fBmalias\fP tries \fB$HOME/.mailrc\fP.  An alternate filename may be
  526. Xspecified on the command line using the \fB-f\fP option (See the OPTIONS
  527. Xsection below).  If the mail command \fBsource\fP is found in the mailrc, it
  528. Xis followed properly.
  529. X
  530. XIf an alias on the command line is not found in the mailrc, then it will be
  531. Xleft alone.  An alias which is found twice (on the command line, as an
  532. Xalias, or as part of a mailing list) will only be returned once.  Aliases
  533. Xmay be more than one level deep.
  534. X
  535. XIf no \fIalias\fP is given on the command line, \fBmalias\fP simply
  536. Xexits.  This is so that it can be used as a front end processor for
  537. Xprograms which don't necessarily take arguments, such as \fBfinger(1)\fP.
  538. XSee the EXAMPLES section below.
  539. X.SH OPTIONS
  540. X.IP \fB-,\fP
  541. XDelimit output with commas.  This is provided for compatibility with RFC822.
  542. X.IP \fB-1\fP
  543. XReturn addresses one per line instead of in stream format.
  544. X.IP "\fB-f \fIfilename\fP"
  545. XUse \fIfilename\fP as the mailrc instead of checking the environment
  546. Xvariable.
  547. X.SH EXAMPLES
  548. X.IP "\fBmalias -1 -f ~joss/.mailrc all | wc -l\fP"
  549. Xwould tell you how many people the user \fBjoss\fP has in his \fBall\fP
  550. Xlist.
  551. X.IP "\fBfinger `malias rochester`"
  552. Xwould \fBfinger\fP all the people in your \fBrochester\fP mailing list.
  553. X.IP "\fBtalk `malias mark`\fP"
  554. Xwould run the command \fBtalk msir_cif@uhura.cc.rochester.edu\fP.  This
  555. Xcan be used in an alias, to make your life easier, as in...
  556. X.IP "\fBalias talk 'talk `malias \e!*`'\fP"
  557. Xso that whenever you run \fBtalk\fP, it will first look through your mail
  558. Xaliases for the address you specify.
  559. X.ad
  560. X.SH ENVIRONMENT
  561. X.IP \fBMAILRC\fP
  562. XName of mailrc file.
  563. X.SH FILES
  564. X.IP \fB~/.mailrc\fP
  565. Xdefault mailrc, if environment variable isn't found.
  566. X.SH "SEE ALSO"
  567. Xmail(1), Mail(1)
  568. X.SH AUTHOR
  569. XMark Sirota (msir_cif@uhura.cc.rochester.edu), Fall 1988
  570. END_OF_FILE
  571. if test 2311 -ne `wc -c <'malias.1'`; then
  572.     echo shar: \"'malias.1'\" unpacked with wrong size!
  573. fi
  574. # end of 'malias.1'
  575. fi
  576. echo shar: End of shell archive.
  577. exit 0
  578.  
  579.